﻿using System;
using System.Collections.Generic;

namespace FibMatrix.DS
{
    [FM_Mono.IgnoreGen]
    public class ObjectPool2<T> : IDisposable where T : class, IDisposable
    {
        private Queue<T> _recycled;

        private Func<T> _factoryFunc;

        private bool _invokeDispose;

#if UNITY_EDITOR
        private int _totalAlloced = 0;
        public int AllRecycled()
        {
            return _totalAlloced - _recycled.Count;
        }
#endif

        public ObjectPool2(int capacity, Func<T> factoryFunc, bool invokeDispose = true)
        {
            if (factoryFunc == null)
            {
                throw new ArgumentNullException("factoryFunc");
            }

            _recycled = capacity <= 0 ? new Queue<T>() : new Queue<T>(capacity);
            _factoryFunc = factoryFunc;
            _invokeDispose = invokeDispose;
        }

        public T Allocate()
        {
            if (_recycled.Count <= 0)
            {
#if UNITY_EDITOR
                _totalAlloced++;
#endif
                return _factoryFunc();
            }

            return _recycled.Dequeue();
        }

        public void Recycle(T t)
        {
            if (null == t)
            {
                return;
            }

            if (this._invokeDispose)
            {
                t.Dispose();
            }

            _recycled.Enqueue(t);
        }

        public void Recycle(ICollection<T> collection)
        {
            if (null == collection || collection.Count == 0)
            {
                return;
            }

            IEnumerator<T> iter = collection.GetEnumerator();

            while (iter.MoveNext())
            {
                iter.Current.Dispose();
                _recycled.Enqueue(iter.Current);
            }

            collection.Clear();
        }

        public void Dispose()
        {
            if (null != _recycled)
            {
                _recycled.Clear();
                _recycled = null;
            }
        }
    }
}
